/// ------------------------------------------------------------------------------------------------------------------------------------
///
/// MIT License
///
/// Permission is hereby granted, free of charge, to any person obtaining a copy
/// of this software and associated documentation files (the "Software"), to deal
/// in the Software without restriction, including without limitation the rights
/// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
/// copies of the Software, and to permit persons to whom the Software is
/// furnished to do so, subject to the following conditions:
///
/// The above copyright notice and this permission notice shall be included in all
/// copies or substantial portions of the Software.
///
/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
/// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
/// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
/// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
/// SOFTWARE.
///
/// Copyright (c) 2024 ycz. All rights reserved.
///
/// Created by ycz on 2024/1/19.
///
/// @file  y_timer.c
///
/// @brief
///     timer 是对常用嵌入式平台定时器接口的封装库
///
/// ------------------------------------------------------------------------------------------------------------------------------------



/// ------------------------------------------------------------------------------------------------------------------------------------
/// 头文件
/// ------------------------------------------------------------------------------------------------------------------------------------

#include "y_timer.h"

#include <stdlib.h>
#include <string.h>
#include "y_sa.h"



/// ------------------------------------------------------------------------------------------------------------------------------------
/// 宏定义
/// ------------------------------------------------------------------------------------------------------------------------------------

#ifdef _Y_LL_H
#    define Y_MALLOC y_ll_malloc
#    define Y_FREE   y_ll_free
#else
#    define Y_MALLOC malloc
#    define Y_FREE   free
#endif



/// ------------------------------------------------------------------------------------------------------------------------------------
/// 全局变量
/// ------------------------------------------------------------------------------------------------------------------------------------

static TIMER_st    *g_timer_arr[20];  ///< 定时器数组索引
static TIMER_DOG_st g_timer_dog;      ///< 定时器看门狗
static int32_t      g_reboot_time;    ///< 定时重启时间
static bool         g_reboot_force;   ///< 是否强制重启标志位



/// ------------------------------------------------------------------------------------------------------------------------------------
/// 公有函数
/// ------------------------------------------------------------------------------------------------------------------------------------

/// @brief   打印 y_timer 版本信息
void y_timer_print_version() {
    YLOG_VERSION("y_timer", Y_TIMER_MAJOR, Y_TIMER_MINOR, Y_TIMER_PATCH);
}

/// @brief 设置定时重启
/// @param   [in] time_ms                  定时重启时间 为 0 不重启
/// @param   [in] is_force                 是否强制重启 不允许再次调用此函数更改重启时间
void y_timer_set_reboot_time(uint32_t time_ms, bool is_force) {
    if (g_reboot_force == false) {
        g_reboot_force = is_force;
        g_reboot_time  = (int32_t) time_ms;
    }
}

/// @brief   喂定时器看门狗
/// @retval  true                          成功
/// @retval  false                         失败
void y_timer_dog_feed() {
    if (g_timer_dog.status == false) {
        g_timer_dog.status = true;
    }
}

/// @brief   创建一个定时器看门狗 主要用于低功耗产品
/// @param   [in] time_ms                  看门狗时间
/// @retval  true                          成功
/// @retval  false                         失败
bool y_timer_dog_create(uint32_t time_ms) {

    // 断言
    YLOGA_FALSE(time_ms);

    g_timer_dog.is_running = true;
    g_timer_dog.status     = true;
    g_timer_dog.time_ms    = time_ms;
    return true;
}

/// @brief   获取定时器触发次数
/// @param   [in] timer                    定时器句柄
/// @return  定时器触发次数
uint8_t y_timer_get_trigger_num(TIMER_st *timer) {

    // 断言
    YLOGA_FALSE(timer);
    return timer->trigger_num;
}

/// @brief   停止运行定时器
/// @param   [in] timer                    定时器句柄
/// @retval  true                          成功
/// @retval  false                         失败
bool y_timer_stop(TIMER_st *timer) {

    // 断言
    YLOGA_FALSE(timer);

    timer->is_running  = false;
    timer->trigger_num = 0;

    return true;
}

/// @brief   开始运行定时器
/// @param   [in] timer                    定时器句柄
/// @param   [in] time_ms                  定时时间
/// @retval  true                          成功
/// @retval  false                         失败
bool y_timer_start(TIMER_st *timer, uint32_t time_ms) {

    // 断言
    YLOGA_FALSE(timer);
    YLOGA_FALSE(time_ms);

    timer->is_running   = true;
    timer->trigger_num  = 0;
    timer->time_ms      = time_ms;
    timer->countdown_ms = 0;

    return true;
}

/// @brief   重新开始运行定时器
/// @param   [in] timer                    定时器句柄
/// @param   [in] time_ms                  定时时间
/// @retval  true                          成功
/// @retval  false                         失败
bool y_timer_restart(TIMER_st *timer, uint32_t time_ms) {

    // 断言
    YLOGA_FALSE(timer);
    timer->is_running  = false;
    timer->trigger_num = 0;

    YLOGA_FALSE(time_ms);
    timer->is_running   = true;
    timer->time_ms      = time_ms;
    timer->countdown_ms = 0;

    return true;
}

/// @brief   销毁定时器
/// @param   [in] timer                    定时器句柄
/// @retval  true                          成功
/// @retval  false                         失败
bool y_timer_destroy(TIMER_st *timer) {

    // 断言
    YLOGA_FALSE(timer);

    Y_FREE(timer);
    return true;
}

/// @brief   创建定时器
/// @param   [in] type                     定时器类型
/// @return  定时器句柄
TIMER_st *y_timer_create(TIMER_TYPE_e type) {

    // 断言
    if (type >= TIMER_ALL) {
        return NULL;
    }

    // 创建定时器
    TIMER_st *timer = (TIMER_st *) Y_MALLOC(sizeof(TIMER_st));
    YLOGA_NULL(timer);
    memset(timer, 0, sizeof(TIMER_st));

    // 初始化
    timer->type = type;

    // 添加到定时数组
    for (int i = 0; i < sizeof(g_timer_arr) / sizeof(g_timer_arr[0]); ++i) {
        if (g_timer_arr[i] == NULL) {
            g_timer_arr[i] = timer;
            return timer;
        }
    }

    Y_FREE(timer);
    return NULL;
}

/// @brief   定时器任务处理    一般放在定时器中断回调中
/// @param   [in] time_ms                  每次定时时间
void y_timer_process(uint32_t time_ms) {

    // y_time 时间滴答时钟
    y_time_tick();

    // 定时数组处理
    for (int i = 0; i < sizeof(g_timer_arr) / sizeof(g_timer_arr[0]); ++i) {
        if (g_timer_arr[i]) {
            // 判断定时器是否打开
            if (g_timer_arr[i]->is_running && g_timer_arr[i]->time_ms) {
                g_timer_arr[i]->countdown_ms += time_ms;  // 倒计时++ time_ms
                // 判断是否到时
                if (g_timer_arr[i]->countdown_ms >= g_timer_arr[i]->time_ms) {
                    g_timer_arr[i]->trigger_num  = g_timer_arr[i]->trigger_num < 0XFF ? g_timer_arr[i]->trigger_num + 1 : 0XFF;  // 触发次数 ++
                    g_timer_arr[i]->countdown_ms = 0;                                                                            // 倒计时复原
                    // 判断定时器触发类型
                    if (g_timer_arr[i]->type == TIMER_ONCE) {
                        g_timer_arr[i]->is_running = false;  // 定时触发一次后 不在触发
                    }
                }
            }
        }
    }

    // 定时器 看门狗 处理 主要用于低功耗产品
    if (g_timer_dog.is_running) {
        if (g_timer_dog.status) {
            g_timer_dog.status       = false;
            g_timer_dog.countdown_ms = 0;  // 看门狗 计时清零
        } else {
            g_timer_dog.countdown_ms += time_ms;
            if (g_timer_dog.countdown_ms >= g_timer_dog.time_ms) {
                YLOGW("timer dog reboot");
                g_timer_dog.countdown_ms = 0;  // 看门狗 计时清零
                y_ll_reboot();                 // 系统重启
            }
        }
    }

    // 定时重启控制
    if (g_reboot_time) {
        g_reboot_time -= (int32_t) time_ms;
        if (g_reboot_time <= 0) {
            YLOGW("timer reboot");
            y_ll_reboot();  // 系统重启
        }
    }
}
